#!/usr/bin/perl
use strict;

package Backup::Create;
# Package to create mysql backups
# Test merge
use DBI;
use Data::Dumper;

my $dbh;

sub new {
	my ($type,$username,$password,$host,$socket) = @_;
	if ( !$username or !$password or !$host ) {
		print STDERR "You must specify your MySQL username, password, and host.\n";
	}
	my $connectionString = "DBI:mysql:information_schema;host=$host;";
	if ( $socket ) {
		$connectionString .= "socket=$socket;";
	}
	my $self = {
		databases=>undef,
		tables=>undef,
		connectionString=>$connectionString,
		username=>$username,
		password=>$password,
		host=>$host,
		socket=>$socket,
		};
	bless($self,$type);
	$self->{databases} = ();
	$self->{tables} = {};
	$dbh = DBI->connect($connectionString,$username,$password) or die("Unable to connect.");
	return $self;
}

sub add {
	my ($self,$database,$table) = @_;
	if ( !$database ) {
		return;
	}
	if ( !$table ) {
		push(@{$self->{databases}},$database);
	} else {
		if ( !(exists $self->{tables}->{$database}) ) {
			$self->{tables}->{$database} = ();
		}
		push(@{$self->{tables}->{$database}}, $table);
	}
}

sub dumpString {
	my ($self) = @_;
	return "mysqldump --compact --triggers --routines --add-drop-table " .($self->{host} ? "-h $self->{host} " : undef).($self->{socket} ? "-S $self->{socket} " : undef)."-u $self->{username} -p$self->{password} ";
}

sub exists {
	my ($self,$database,$table) = @_;
	if (!$database) {
		return 0;
	}
	my @databases = $self->getDatabases();
	my %match = map{ $_ => 1 } @databases;
	if ( $match{$database} ) { 
		if ( !$table ) {
			return 1;
		} else {
			my @tables = $self->getTables($database);
			return $table ~~ @tables;
		}
	} else {
		return 0;
	}
}

sub save {
	my ($self,$directory) = @_;
	#my $dbh = DBI->connect($self->{connectionString},$self->{username},$self->{password});
	my @databases = $self->getDatabases();
	my %allDatabases = map{ $_ => 1 } @databases;
	my %backupDatabases = map { $_ => 1 } @{$self->{databases}};
	if ( !(-d $directory) ) {
		mkdir ($directory);
	}
	foreach (@{$self->{databases}}) {
		if ( !(-d "$directory/$_")) {
			mkdir ("$directory/$_");
		}
		if ( $allDatabases{$_} ) {
			my @tables = $self->getTables($_);
			print "Backing up database $_\n";
			foreach my $table (@tables) {
				#mysql dump
				print "\t$table\n";
				system($self->dumpString()." $_ --tables $table > $directory/$_/$table.sql");
			}
		} else {
			print STDERR "Database $_ does not exist. Skipping...\n";
			next;
		}
	}
	foreach ( keys %{$self->{tables}} ) {
		if ( $backupDatabases{$_} ) {
			next;
		}
		if ( !($allDatabases{$_}) ) {
			print "Database $_ does not exist. Skipping...\n";
			next;
		}
		if ( !(-d "$directory/$_")) {
			mkdir ("$directory/$_");
		}
		my @tables = $self->getTables($_);
		my %allTables = map { $_ => 1 } @tables;
		print "Backing up specific tables from $_\n";
		foreach my $table ( @{$self->{tables}->{$_}} ) {
			if ( $allTables{$table} ) {
				print "\t$table\n";
				system($self->dumpString()." $_ --tables $table > $directory/$_/$table.sql");		
			} else {
				print STDERR "Table $_.$table does not exist. Skipping...\n";
				next;
			}
		}
	}
	$self->createINI($directory);
	$self->compress($directory);
	print "Backup saved to $directory.\n";
}	

sub getTables {
	my($self,$database) = @_;
	#my $dbh = $self->{dbh};
	$dbh->do("USE $database;");
	my $tables = $dbh->selectcol_arrayref("SHOW TABLES;");
	return @$tables;
}

sub getDatabases {
	my ($self) = @_;
	#my $dbh = $self->{dbh};
	my $databases = $dbh->selectcol_arrayref("SHOW DATABASES;");
	return @$databases;
}

sub createINI {
	my($self,$directory) = @_;
	my @databases = @{$self->{databases}};
	my %allDatabases = map { $_ => 1 } @databases;
	open(FILE,">$directory/backup.ini");
	foreach (@databases){
		if ( $self->exists($_) ) {
			print FILE "$_\n";
			my @tablesInDatabase = $self->getTables($_);
			foreach my $tableInDatabase (@tablesInDatabase) {
				print FILE "\t$tableInDatabase\n";
			}
		}
	}
	foreach ( keys %{$self->{tables}} ) {
		if ( $allDatabases{$_} || !($self->exists($_))  ) {
			next;
		}
		print FILE "$_\n";
		foreach my $table ( @{$self->{tables}->{$_}} ) {
			if ( $self->exists($_,$table) ) {
				print FILE "\t$table\n";
			}
		}
	}
	close(FILE);
}

sub compress {
	my ($self,$directory) = @_;
	opendir(DIR,$directory) or die("Couldn't open directory to compress.");
	my @folders = readdir(DIR);
	foreach (@folders) {
		if (-d "$directory/$_" && !($_ =~ /\.$/)) {
			system("cd $directory;tar -czf $_.tar.gz $_;rm -rf $_;");
		}
	}
	closedir(DIR);
}
1;
